package com.hk.core.autoconfigure.data.elasticsearch;

import com.hk.commons.ssl.CompositeTrustManager;
import com.hk.commons.util.SnowflakeUtils;
import com.hk.core.elasticsearch.domain.AbstractSnowflakeIdPersistable;
import com.hk.core.elasticsearch.repository.BaseReactiveElasticsearchRepositoryFactoryBean;
import io.netty.handler.ssl.SslProtocols;
import lombok.SneakyThrows;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchConfiguration;
import org.springframework.data.elasticsearch.config.EnableReactiveElasticsearchAuditing;
import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback;
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;


/**
 * ElasticSearch Reactive
 *
 * @author Kevin
 */
@AutoConfiguration
@EnableReactiveElasticsearchAuditing
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass({ReactiveElasticsearchClient.class, WebClient.class, HttpClient.class})
@EnableReactiveElasticsearchRepositories(basePackages = {"**.repository.elasticsearch"},
        repositoryFactoryBeanClass = BaseReactiveElasticsearchRepositoryFactoryBean.class)
public class ReactiveElasticsearchAutoConfiguration extends ReactiveElasticsearchConfiguration {

    private final ElasticsearchProperties elasticsearchProperties;

    public ReactiveElasticsearchAutoConfiguration(ElasticsearchProperties elasticsearchProperties) {
        this.elasticsearchProperties = elasticsearchProperties;
    }

    /**
     * SSL 配置
     */
    @Override
    @SneakyThrows
    public ClientConfiguration clientConfiguration() {
        SSLContext context = SSLContext.getInstance(SslProtocols.TLS_v1_3);
        context.init(null, new TrustManager[]{new CompositeTrustManager()}, null);
        return ClientConfiguration.builder()
                .connectedTo(elasticsearchProperties.getUris().toArray(String[]::new))
                .usingSsl(context)
                .withConnectTimeout(elasticsearchProperties.getSocketTimeout())
                .withSocketTimeout(elasticsearchProperties.getSocketTimeout())
                .withPathPrefix(elasticsearchProperties.getPathPrefix())
                .withBasicAuth(elasticsearchProperties.getUsername(), elasticsearchProperties.getPassword())
                .build();
    }

//    /**
//     * 注册类型转换
//     */
//    @Bean
//    @Override
//    public ElasticsearchCustomConversions elasticsearchCustomConversions() {
//        List<GenericConverter> converters = new ArrayList<>();
//        converters.add(Jsr310Converters.StringToLocalDateConverter.INSTANCE);
//        converters.add(Jsr310Converters.StringToLocalTimeConverter.INSTANCE);
//        converters.add(Jsr310Converters.StringToLocalDateTimeConverter.INSTANCE);
//        converters.add(Jsr310Converters.StringToYearConverter.INSTANCE);
//        converters.add(Jsr310Converters.StringToYearMonthConverter.INSTANCE);
//        return new ElasticsearchCustomConversions(converters);
//    }

    /**
     * 保存时，如果没有设置id，则设置一个
     */
    @Bean
    @Order(value = 1)
    public ReactiveBeforeConvertCallback<AbstractSnowflakeIdPersistable> elasticSearchSnowflakeIdBeforeSaveCallback() {
        return (entity, index) -> {
            if (entity.isNew()) {
                entity.setId(SnowflakeUtils.getIdGenerator().generate());
            }
            return Mono.just(entity);
        };
    }


}
